import http from '@ohos.net.http';
import { BusinessError } from '@ohos.base';
import Url from '@ohos.url'
import { promptAction } from '@kit.ArkUI';

interface WTROneFile {
  name: string, //表单上传文件的参数名
  path: string, //文件路径
}

interface WTRHttpOptions {
  url: string;

  //回调二选一
  callback?: (err: Error, result: string) => void;
  callbackAll?: (err: BusinessError, data: http.HttpResponse) => void;

  //可选部分
  method?: string, //默认GET
  isJson?: boolean, //默认true
  param?: Object,
  header?: Object,
  timeout?: number, //默认30秒超时
  usingCache?: boolean; //默认false
  caPath?: string;
  clientCert?: http.ClientCert;
  multiFormDataList?: Array<http.MultiFormData>;

  //上传进度提示 pro: 0-1
  uploadPro?: (pro: number) => void;

  //下载进度提示 pro: 0-1
  downloadPro?: (pro: number) => void;
}

class _wtrhttp {
  GET(url: string, callback: (err: Error, result: string) => void): http.HttpRequest;

  /*
   * 如果打开属性了混淆，param的参数需要带引号写成字符串，例如：
   * {
   *    'name':'ASD'
   * }
   * */
  GET(url: string, param: Object, callback: (err: Error, result: string) => void): http.HttpRequest;

  GET(...list): http.HttpRequest {
    if (list.length == 2) {
      return this.req({
        url: list[0],
        callback: list[1],
      })
    } else if (list.length == 3) {
      return this.req({
        url: list[0],
        param: list[1],
        callback: list[2],
      })
    }
  };

  /*
   * 如果打开属性了混淆，param的参数需要带引号写成字符串，例如：
   * {
   *    'name':'ASD'
   * }
   * */
  POST(url: string, param: Object, callback: (err: Error, result: string) => void): http.HttpRequest;

  POST(url: string, param: Object, isJson: boolean, callback: (err: Error, result: string) => void): http.HttpRequest;

  POST(...list): http.HttpRequest {
    if (list.length == 3) {
      return this.req({
        method: 'POST',
        url: list[0],
        param: list[1],
        callback: list[2],
      })
    } else if (list.length == 4) {
      return this.req({
        method: 'POST',
        url: list[0],
        param: list[1],
        isJson: list[2],
        callback: list[3],
      })
    }
  };

  PUT(url: string, param: Object, callback: (err: Error, result: string) => void): http.HttpRequest;

  PUT(url: string, param: Object, isJson: boolean, callback: (err: Error, result: string) => void): http.HttpRequest;

  PUT(...list): http.HttpRequest {
    if (list.length == 3) {
      return this.req({
        method: 'PUT',
        url: list[0],
        param: list[1],
        callback: list[2],
      })
    } else if (list.length == 4) {
      return this.req({
        method: 'PUT',
        url: list[0],
        param: list[1],
        isJson: list[2],
        callback: list[3],
      })
    }
  };

  DELETE(url: string, param: Object, callback: (err: Error, result: string) => void): http.HttpRequest;

  DELETE(url: string, param: Object, isJson: boolean, callback: (err: Error, result: string) => void): http.HttpRequest;

  DELETE(...list): http.HttpRequest {
    if (list.length == 3) {
      return this.req({
        method: 'DELETE',
        url: list[0],
        param: list[1],
        callback: list[2],
      })
    } else if (list.length == 4) {
      return this.req({
        method: 'DELETE',
        url: list[0],
        param: list[1],
        isJson: list[2],
        callback: list[3],
      })
    }
  };

  /*
   *  HEAD 请求可以直接用req 需要设置 callbackAll
   * */

  //表单上传
  uploadFile(options: WTRHttpOptions, fileArray: Array<WTROneFile>) {
    let multiFormDataList: Array<http.MultiFormData> = new Array<http.MultiFormData>();
    for (let one in options.param) {
      multiFormDataList.push({
        name: "" + one,
        contentType: '', //text/plain
        data: "" + options.param[one],
      });
    }
    for (let i = 0; i < fileArray.length; i++) {
      let onePath = fileArray[i].path;
      let name = fileArray[i].name;

      let gang = onePath.lastIndexOf('/');
      let filename = onePath.substring((gang > 0 && gang + 1 < onePath.length) ? gang + 1 : 0, onePath.length);

      //可能需要根据后缀确定contentType
      // let dian = onePath.lastIndexOf('.');
      // let ext = onePath.substring((dian > 0 && dian + 1 < onePath.length) ? dian + 1 : 0, onePath.length);
      // console.log("ext:", ext);

      multiFormDataList.push({
        name: '' + name,
        contentType: 'application/octet-stream',
        filePath: onePath,
        remoteFileName: filename
      });
    }
    options.param = undefined;
    options.method = 'POST';
    options.multiFormDataList = multiFormDataList;
    this.req(options);
  }

  //全局增加的Header
  globalHeader: Record<string, string | number> = {};

  showLog: boolean = false; //是否打印请求数据和返回数据

  //封装json和urlencoded提交
  req(options: WTRHttpOptions): http.HttpRequest {

    let url: string = options.url;
    let callback: (err: Error, result: string) => void = options.callback;

    let method: string = options.method === undefined ? 'GET' : options.method;
    let isJson: boolean = options.isJson === undefined ? true : options.isJson;
    let param: Object = options.param;
    let inHeader: Object = options.header === undefined ? {} : options.header;
    let timeout: number = options.timeout === undefined ? 30000 : options.timeout; //默认30秒超时
    let usingCache: boolean = options.usingCache === undefined ? false : options.usingCache;
    let callbackAll: (err: BusinessError, data: http.HttpResponse) => void = options.callbackAll;

    let bodyData: string | Object | ArrayBuffer;
    let bodyDataType: http.HttpDataType;

    method = method.toUpperCase();

    if (method == http.RequestMethod.GET) {
      //把参数集中到url
      let urlObject = Url.URL.parseURL(url);
      for (let one in param) {
        urlObject.params.append(one, '' + param[one]);
      }
      url = urlObject.toString();
    } else if (param) {
      //把参数放到body
      if (isJson) {
        let json: string = JSON.stringify(param);
        bodyData = json;
        bodyDataType = http.HttpDataType.STRING;
      } else {
        let params = new Url.URLParams();
        for (let one in param) {
          params.append(one, '' + param[one]);
        }
        bodyData = params.toString();
        bodyDataType = http.HttpDataType.STRING;
      }
    }

    let header = {};
    for (let one in this.globalHeader) {
      header[one] = this.globalHeader[one];
    }
    for (let one in inHeader) {
      header[one] = inHeader[one];
    }

    if (options.multiFormDataList) {
      header['Content-Type'] = 'multipart/form-data';
    } else {
      header['Content-Type'] = isJson ? 'application/json' : 'application/x-www-form-urlencoded';
    }

    return this.createHttpAndReq(url, {
      method: method as http.RequestMethod,
      header: header,
      extraData: bodyData,
      expectDataType: bodyDataType,
      usingCache: usingCache, // 可选，默认为true
      priority: 1, // 可选，默认为1
      connectTimeout: timeout, // 可选，默认为60000ms
      readTimeout: timeout, // 可选，默认为60000ms
      usingProtocol: http.HttpProtocol.HTTP1_1,
      usingProxy: true, // 可选，默认不使用网络代理，自API 10开始支持该属性
      caPath: options.caPath,
      clientCert: options.clientCert,
      multiFormDataList: options.multiFormDataList
    }, (err: BusinessError, data: http.HttpResponse) => {
      if (this.showLog) {
        console.log('请求结果:', (err ? "err:" + err.message : data.result));
      }
      try {
        if (callbackAll) {
          callbackAll(err, data);
        } else if (callback) {
          if (err) {
            callback(err, undefined);
          } else {
            if (data.resultType == http.HttpDataType.STRING) {
              callback(err, data.result as string);
            } else {
              callback(err, JSON.stringify(data.result));
            }
          }
        }
      } catch (e) {
        let msg = `${url}\n返回数据操作崩溃：\n${e}`;
        if (this.showLog) {
          promptAction.showToast({ message: msg, duration: 10000 })
          console.error(msg);
        }
        err = { code: -1, message: msg, name: '返回数据操作崩溃' };
        if (callbackAll) {
          callbackAll(err, undefined);
        } else if (callback) {
          callback(err, undefined);
        }
      }
    }, options.uploadPro, options.downloadPro);
  }

  createHttpAndReq(url: string, options: http.HttpRequestOptions,
    callback: (err: BusinessError, data: http.HttpResponse) => void,
    uploadPro?: (pro: number) => void,
    downloadPro?: (pro: number) => void,
  ): http.HttpRequest {
    let httpRequest = http.createHttp();
    if (this.changeUrl) {
      url = this.changeUrl(url, options);
    }
    if (this.changeOptions) {
      options = this.changeOptions(url, options);
    }

    if (this.showLog) {
      console.log("请求开始：", options.method, ":", url);
      console.log("header:", JSON.stringify(options.header));
      console.log("bodyData:", options.extraData);
    }

    if (uploadPro) {
      httpRequest.on('dataSendProgress', (data: http.DataSendProgressInfo) => {
        uploadPro(data.sendSize / data.totalSize);
      });
    }
    if (downloadPro) { //开启流式下载
      httpRequest.on('dataReceiveProgress', (data: http.DataReceiveProgressInfo) => {
        downloadPro(data.receiveSize / data.totalSize);
      });

      let _header: Object = {};
      httpRequest.on('headersReceive', (header: Object) => {
        _header = header;
      });

      let res = new ArrayBuffer(0);
      httpRequest.on('dataReceive', (data: ArrayBuffer) => {
        const newRes = new ArrayBuffer(res.byteLength + data.byteLength);
        const resView = new Uint8Array(newRes);
        resView.set(new Uint8Array(res));
        resView.set(new Uint8Array(data), res.byteLength);
        res = newRes;
      })

      httpRequest.requestInStream(url, options, (err: BusinessError, data: number) => {
        callback(err, {
          header: _header,
          responseCode: data,
          result: res,
          resultType: http.HttpDataType.ARRAY_BUFFER,
          cookies: '',
          performanceTiming: {
            dnsTiming: 0,
            tcpTiming: 0,
            tlsTiming: 0,
            totalFinishTiming: 0,
            totalTiming: 0,
            firstSendTiming: 0,
            firstReceiveTiming: 0,
            redirectTiming: 0,
            responseHeaderTiming: 0,
            responseBodyTiming: 0,
          }
        });
        if (uploadPro) {
          httpRequest.off('dataSendProgress');
        }
        if (downloadPro) {
          httpRequest.off('dataReceiveProgress');
        }
        httpRequest.off('headersReceive');
        httpRequest.off('dataReceive');
        httpRequest.destroy();
      });
      return
    }

    httpRequest.request(url,
      options,
      (err: BusinessError, data: http.HttpResponse) => {
        callback(err, data);
        if (uploadPro) {
          httpRequest.off('dataSendProgress');
        }
        if (downloadPro) {
          httpRequest.off('dataReceiveProgress');
        }
        httpRequest.destroy();
      }
    );
    return httpRequest;
  }

  //用于根据情况改变请求内容
  changeUrl: (url: string, options: http.HttpRequestOptions) => string;
  changeOptions: (url: string, options: http.HttpRequestOptions) => http.HttpRequestOptions;
}

let wtrhttp = new _wtrhttp();

export default wtrhttp;